package com.vision.admin.activitylog.cl.ui;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import net.customware.gwt.dispatch.client.DefaultExceptionHandler;
import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.dispatch.client.standard.StandardDispatchAsync;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.shared.DateTimeFormat;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.Style.SelectionMode;
import com.sencha.gxt.data.client.loader.RpcProxy;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.loader.LoadResultListStoreBinding;
import com.sencha.gxt.data.shared.loader.PagingLoadConfig;
import com.sencha.gxt.data.shared.loader.PagingLoader;
import com.sencha.gxt.widget.core.client.TabItemConfig;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GridView;
import com.sencha.gxt.widget.core.client.grid.filters.GridFilters;
import com.sencha.gxt.widget.core.client.grid.filters.StringFilter;
import com.sencha.gxt.widget.core.client.toolbar.PagingToolBar;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;
import com.vision.admin.activitylog.cl.ActivityLogProperties;
import com.vision.admin.cl.AdminTasks;
import com.vision.admin.cl.resource.AdminResources;
import com.vision.core.cl.ui.EnumFilter;
import com.vision.core.cl.ui.TabItemPanel;
import com.vision.core.cl.ui.UI;
import com.vision.core.cl.ui.component.BasicGridView;
import com.vision.core.cm.Constants;
import com.vision.core.cm.action.GetActivityLogsAction;
import com.vision.core.cm.action.GetActivityLogsResult;
import com.vision.core.cm.data.ActivityType;
import com.vision.core.cm.data.Domain;
import com.vision.core.cm.db.data.ActivityLog;

/**
 * 
 * @author Mark
 * 
 */
public class ActivityLogsPanel extends TabItemPanel {

	interface Binder extends UiBinder<Widget, ActivityLogsPanel> { }

	private static final Binder binder = GWT.create(Binder.class);
	
	private static DateTimeFormat timestampFormat = DateTimeFormat.getFormat("MM/dd/yyyy h:mm a");
	private static DateTimeFormat withinYearFormat = DateTimeFormat.getFormat("d MMM h:mm a");
	private static DateTimeFormat todayFormat = DateTimeFormat.getFormat("h:mm a");
	
	@UiField VerticalLayoutContainer mainPanel;
	
	@UiField ToolBar toolbar;
	@UiField TextButton refreshBtn;
	
	@UiField Grid<ActivityLog<?>> grid;
	@UiField PagingToolBar pagingToolbar;
	
	PagingLoader<PagingLoadConfig, GetActivityLogsResult> loader;
	
	DispatchAsync dispatch = new StandardDispatchAsync(new DefaultExceptionHandler());
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public ActivityLogsPanel() {
		setWidget(binder.createAndBindUi(this));
		
		// Initialize loaders
		RpcProxy<PagingLoadConfig, GetActivityLogsResult> proxy = new RpcProxy<PagingLoadConfig, GetActivityLogsResult>() {
		    @Override
		    public void load(PagingLoadConfig loadConfig, AsyncCallback<GetActivityLogsResult> callback) {
		    	dispatch.execute(new GetActivityLogsAction(loadConfig.getOffset(), loadConfig.getLimit()), callback);
		    }
	    };
	    
	    loader = new PagingLoader<PagingLoadConfig, GetActivityLogsResult>(proxy);
        loader.setRemoteSort(true);
        loader.addLoadHandler(new LoadResultListStoreBinding<PagingLoadConfig, ActivityLog<?>, GetActivityLogsResult>(grid.getStore()));
        
        grid.setLoader(loader);
        grid.setLoadMask(true);
		
		pagingToolbar.bind(loader);
	}
	
	// UiFactory Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * Used to create the 'grid' field in the XML file. 
	 * 
	 * @return
	 */
	@UiFactory
	Grid<ActivityLog<?>> initializeGrid() {
		ActivityLogProperties props = GWT.create(ActivityLogProperties.class);

		List<ColumnConfig<ActivityLog<?>, ?>> columns = new ArrayList<ColumnConfig<ActivityLog<?>, ?>>();

		columns.add(UI.column(props.timestamp(), 100, "Timestamp", new AbstractCell<Timestamp>() {
			@Override
			public void render(Context context, Timestamp value, SafeHtmlBuilder sb) {
				long diff = System.currentTimeMillis() - value.getTime();
				DateTimeFormat format = timestampFormat;
				if (diff < Constants.DAY_IN_MILLIS) // within the day
					format = todayFormat;
				else if (diff < Constants.DAY_IN_MILLIS * 365) // within the year
					format = withinYearFormat;
				
				sb.append(SafeHtmlUtils.fromString(format.format(value)));
			}
		}));
		
		columns.add(UI.column(props.user(), 100, "Username"));
		
		columns.add(UI.column(props.domain(), 100, "Domain"));
		columns.add(UI.column(props.type(), 80, "Type"));
		columns.add(UI.column(props.serializedString(), 380, "Detail", new AbstractCell<String>() {
			@Override
			public void render(Context context, String value, SafeHtmlBuilder sb) {
				sb.append(SafeHtmlUtils.fromString(value));
			}
		}));
		
		ColumnModel<ActivityLog<?>> cm = new ColumnModel<ActivityLog<?>>(columns);

		final Grid<ActivityLog<?>> grid = new Grid<ActivityLog<?>>(new ListStore<ActivityLog<?>>(props.key()), cm);
		grid.setAllowTextSelection(false);
		grid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		
		// Setup View
		GridView<ActivityLog<?>> view = new BasicGridView<ActivityLog<?>>();
		view.setEmptyText("There are no logs to display.");
		view.setAutoExpandColumn(columns.get(columns.size() - 1));
		grid.setView(view);
		
		// Setup Filters
		StringFilter<ActivityLog<?>> userFilter = new StringFilter<ActivityLog<?>>(props.user());
		EnumFilter<ActivityLog<?>, Domain> domainFilter = new EnumFilter<ActivityLog<?>, Domain>(props.domain(), Domain.values());
		EnumFilter<ActivityLog<?>, ActivityType> typeFilter = new EnumFilter<ActivityLog<?>, ActivityType>(props.type(), ActivityType.values());
		
		GridFilters<ActivityLog<?>> filters = new GridFilters<ActivityLog<?>>();
		filters.initPlugin(grid);
		filters.setLocal(true);
		
		filters.addFilter(userFilter);
		filters.addFilter(domainFilter);
		filters.addFilter(typeFilter);
		
		return grid;
	}
	
	// Listeners %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	// Called when the 'Refresh' button is clicked
	@UiHandler("refreshBtn")
	void refreshClicked(SelectEvent e) {
		loadData();
	}
	 
	// ITabItemPanel Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Override
	public String getPanelId() {
		return AdminTasks.ACTIVITY_LOG.getId();
	}
	
	@Override
	public TabItemConfig getConfig() {
		if (config == null) {
			config = new TabItemConfig("Activity Logs", true);
			config.setIcon(AdminResources.INSTANCE.activity_log());
		}
		return config;
	}
	
	@Override
	public void loadData() {
		// Load data
		Log.debug("Loading logs...");
		
		loader.load();
	}
	
}
